package com.sk.bilibili.interceptor;

/**
 * @author 邵康
 * @date 2021/12/18 15:07
 * 插件只需要注入容器即可 例如分页插件
 */

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.sk.bilibili.handler.PostValueHandler;
import com.sk.bilibili.handler.numHandler.BaseNumHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

//  注意 继承层次 不能太深  最多一层
public abstract class BaseInterceptor<H> implements Interceptor , InitializingBean {

    private Map<Class<?>,List<H>> handlerMap;//可能有多个 处理器 处理同一类型
    private Map<Class<?>, List<H>> cacheHandler;
    private Set<Class<?>> handledClass;

    @Override
    public void afterPropertiesSet() throws Exception {
        cacheHandler=new HashMap<>();
        handledClass=new HashSet<>();
    }

    @Autowired
    public void setDefaultValueHandler(H[] handlers){
        handlerMap=new HashMap<>();
        for (H handler : handlers) {
            Class<?> clazz=parseClass(handler.getClass());
            if(!handlerMap.containsKey(clazz))handlerMap.put(clazz,new ArrayList<>());
            handlerMap.get(clazz).add(handler);
        }
    }

    //不再检查  泛型  找到第一个泛型信息就返回  实现类也要注意 把处理类型放在第一个
    private Class<?> parseClass(Class<?> clazz) {
        while (clazz!=null){//递归找 一次
            Type[] types = clazz.getGenericInterfaces();
            for (Type type : types) {
                if(type instanceof ParameterizedType){
                    ParameterizedType parameterizedType= (ParameterizedType) type;
                    return (Class<?>) parameterizedType.getActualTypeArguments()[0];
                }
            }//找完接口找 类对象
            Type type = clazz.getGenericSuperclass();
            if(type instanceof ParameterizedType){
                ParameterizedType parameterizedType= (ParameterizedType) type;
                return (Class<?>) parameterizedType.getActualTypeArguments()[0];
            }
            clazz=clazz.getSuperclass();
        }
        throw new RuntimeException("没有指定对应的泛型或没有继承PostValueHandler");
    }

    // 暂时只对 List  IPage  解封
    protected void handleValue(Object res) {
        if(res instanceof List){
            handleListValue((List) res);
        }else if(res instanceof IPage){
            IPage page= (IPage) res;
            handleListValue(page.getRecords());
        }else {
            Class<?> clazz = res.getClass();
            if(!handledClass.contains(clazz)){
                handleClass(clazz);
            }
            List<H> handlers = cacheHandler.get(clazz);
            if(handlers==null)return;//不支持直接返回
            handlers.forEach(handler->handleValue(handler,res));
        }
    }

    protected abstract void handleValue(H handler, Object res);

    private void handleClass(Class<?> clazz) {
        handledClass.add(clazz);
        for (Class<?> key:handlerMap.keySet()){
            if(key.isAssignableFrom(clazz)){//一个类可能需要多个 值的后置处理  考虑继承
                if(!cacheHandler.containsKey(clazz))cacheHandler.put(clazz,new ArrayList<>());
                cacheHandler.get(clazz).addAll(handlerMap.get(key));
            }
        }
    }

    private void handleListValue(List list) {
        for (Object obj:list){
            handleValue(obj);
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {}

}
